#include <odpapi.h>
#include <string.h>
#include <stdio.h>
#include <cjson.h>
#include <time.h>

#define ODPAPI_VERSION "1.0"

#ifdef WIN32
#define snprintf _snprintf
#define strdup _strdup
#endif

char* odpapi_format_common_result_text(char* buffer,                  
	                                   size_t length,                    
									   enum ODPAPI_COMMONERROR error)    
{
	memset(buffer, 0, length);

	switch(error)
	{
	default:
		snprintf(buffer, length, "Unknown error");
		break;
	case ODPAPI_COMMONERROR_OK:  
		snprintf(buffer, length, "OK");
		break;
	case ODPAPI_COMMONERROR_PARSEFAILED:
		snprintf(buffer, length, "JSON parse error");
		break;
	case ODPAPI_COMMONERROR_NOTOFFERED:
		snprintf(buffer, length, "API option not offered");
		break;
	case ODPAPI_COMMONERROR_NOTPERMITTED:     
		snprintf(buffer, length, "API option not permitted");
		break;
	case ODPAPI_COMMONERROR_FAILEDAUTH:
		snprintf(buffer, length, "Failed authorization");
		break;
	case ODPAPI_COMMONERROR_ERRORCOMEBACK:    
		snprintf(buffer, length, "Service temporarily unavailable. Come back later");
		break;
	case ODPAPI_COMMONERROR_EXCEEDEDALLOWANCE:
		snprintf(buffer, length, "Exceeded API allowance");
		break;
	case ODPAPI_COMMONERROR_INVALIDUUID:      
		snprintf(buffer, length, "Unable to interpret UUID");
		break;
	case ODPAPI_COMMONERROR_MISSINGARGUMENT:
		snprintf(buffer, length, "Missing argument");
		break;
	case ODPAPI_COMMONERROR_SOURCELIBRARYNOTKNOWN:
		snprintf(buffer, length, "Source Library is unknown");
		break;
	case ODPAPI_COMMONERROR_TARGETLIBRARYNOTKNOWN:
		snprintf(buffer, length, "Target Library is unknown");
		break;
	case ODPAPI_COMMONERROR_TARGETLIBRARYSAME:
		snprintf(buffer, length, "Target Library is the same as the Source Library");
		break;
	}

	return buffer;
}

void odpapi_response_epilog(cJSON *root,
							enum ODPAPI_COMMONERROR error,
							char* hint)
{
	char	work[256];
	cJSON	*response = NULL;
	cJSON	*tmp;

	odpapi_format_common_result_text(work, sizeof(work), error);

	//*
	//* Get the first child
	//*
	response = odpapi_request_get_value(root, "response");

	//*
	//* If we don't have a response section then create one
	//*
	if ( response == NULL )
	{
		response = cJSON_CreateObject();
		cJSON_AddItemToObject(root, "response", response);
		cJSON_AddNumberToObject(response, "result", error);
		cJSON_AddStringToObject(response, "result_text", work);

		if ( hint )
		{
			cJSON_AddStringToObject(response, "result_hint", hint);
		}
	}
	else
	{
		if ( hint )
		{
			cJSON_AddStringToObject(response, "result_hint", hint);
		}

		//*
		//* If we do have a response section then reset the result and result_text
		//*
		tmp = response->child;

		while ( tmp )
		{
			if ( tmp->string && (strcmp(tmp->string, "result")==0) )
			{
				tmp->valuedouble = tmp->valueint = error;
			}
			else
			{
				if ( tmp->string && (strcmp(tmp->string, "result_text")==0) )
				{
					if ( tmp->valuestring )
						free(tmp->valuestring);

					tmp->valuestring = strdup(work);
				}
			}

			tmp = tmp->next;
		}
	}
}

cJSON* odpapi_response_prolog(cJSON *root,
							  char* adaptername)
{
	cJSON		*meta = cJSON_CreateObject();
	cJSON		*response = cJSON_CreateObject();
	time_t		tNow;
	struct tm*	pTM;
	char		buffer[256];

	//*
	//* Set the time
	//*
	strcpy(buffer, "unknown-time");

	tNow = time(NULL);
	pTM = localtime(&tNow);

	if ( pTM )
	{
		strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %z",  pTM);
	}
	
	//*
	//* Add the Meta section
	//*
	cJSON_AddItemToObject(root, "meta", meta);
	cJSON_AddStringToObject(meta, "created", buffer); 
	cJSON_AddStringToObject(meta, "creator", adaptername); 

	snprintf(buffer, sizeof(buffer), "ODPAPI Version: %s", ODPAPI_VERSION);
	cJSON_AddStringToObject(meta, "version", buffer); 
	
	//*
	//* Add the response section and add some placeholder data
	//*
	cJSON_AddItemToObject(root, "response", response);
	cJSON_AddNumberToObject(response, "result", ODPAPI_COMMONERROR_UNKNOWN);
	cJSON_AddStringToObject(response, "result_text", "");

	return response;
}

cJSON* odpapi_request_get_request(cJSON *root)
{
	cJSON* request = NULL;

	if ( root && root->child )
	{
		request = root->child->next;

		while ( request )
		{
			if ( request->string && (strcmp(request->string, "request")==0) )
			{
				break;
			}

			request = request->next;	
		}
	}

	return request;
}

cJSON* odpapi_request_get_value(cJSON *json, char* key)
{
	cJSON* result = NULL;

	if ( json && json->child )
	{
		result = json->child;

		while ( result )
		{
			if ( result->string && (strcmp(result->string, key)==0) )
			{
				break;
			}

			result = result->next;	
		}
	}

	return result;
}


void odpapi_move_response_helper(cJSON *responsearray,
							     enum ODPAPI_MOVESTATUS status,
								 int sequence,
								 char* id,
								 char* type,
								 char* movedate,
								 char* hint)
{
	cJSON* response = cJSON_CreateObject();
	cJSON_AddItemToArray(responsearray, response);

	cJSON_AddNumberToObject(response, "sequence", sequence);
	cJSON_AddNumberToObject(response, "status", status);
	
	if ( hint && strlen(hint) )
	{
		cJSON_AddStringToObject(response, "status_hint", hint);
	}

	if ( id && strlen(id) )
	{
		cJSON_AddStringToObject(response, "id", id);
	}

	if ( type && strlen(type) )
	{
		cJSON_AddStringToObject(response, "type", type);
	}

	if ( movedate && strlen(movedate) )
	{
		cJSON_AddStringToObject(response, "move_date", movedate);
	}
}

void odpapi_inventory_response_helper(cJSON *responsearray,
							          enum ODPAPI_INVENTORYSTATUS status,
								      int sequence,
								      char* id,
								      char* type,
									  char* description,
									  char* movedate,
									  int encrypted,
									  int scratch,
									  int automatemovedate)
{
	cJSON* response = cJSON_CreateObject();
	cJSON_AddItemToArray(responsearray, response);

	cJSON_AddNumberToObject(response, "sequence", sequence);
	cJSON_AddNumberToObject(response, "status", status);

	if ( id && strlen(id) )
	{
		cJSON_AddStringToObject(response, "id", id);
	}

	if ( type && strlen(type) )
	{
		cJSON_AddStringToObject(response, "type", type);
	}

	if ( description && strlen(description) )
	{
		cJSON_AddStringToObject(response, "description", description);
	}

	if ( movedate && strlen(movedate) )
	{
		cJSON_AddStringToObject(response, "move_date", movedate);
	}

	cJSON_AddBoolToObject(response, "encrypted", encrypted);
	cJSON_AddBoolToObject(response, "scratch", scratch);

	if ( automatemovedate )
	{
		cJSON_AddBoolToObject(response, "automate_move_date", 1);
	}
}


cJSON* odpapi_list_response_helper(cJSON *responsearray,
				 			       int sequence,
								   char* description,
								   char* guid,
								   unsigned int capacity,
								   unsigned int capacityused,
								   unsigned int movingin,
								   unsigned int movingout,
								   int automatemovedate,
								   char **targetguids)
{
	int		i;
	cJSON*	response = cJSON_CreateObject();
	cJSON*  targets;
	cJSON*	target;

	cJSON_AddItemToArray(responsearray, response);
	cJSON_AddNumberToObject(response, "sequence", sequence);

	if ( automatemovedate )
	{
		cJSON_AddBoolToObject(response, "automate_move_date", 1);
	}

	if ( guid && strlen(guid) )
	{
		cJSON_AddStringToObject(response, "guid", guid);
	}

	if ( description && strlen(description) )
	{
		cJSON_AddStringToObject(response, "description", description);
	}

	//*
	//* Now add each of the target GUIDs
	//*
	targets = cJSON_CreateArray();
	cJSON_AddItemToObject(response, "targets", targets);

	for(i=0; *targetguids; targetguids++)
	{
		target = cJSON_CreateString(*targetguids);
		cJSON_AddItemToArray(targets, target);
	}

	cJSON_AddNumberToObject(response, "capacity_total", capacity);
	cJSON_AddNumberToObject(response, "capacity_used", capacityused);
	cJSON_AddNumberToObject(response, "moving_in", movingin);
	cJSON_AddNumberToObject(response, "moving_out", movingout);

	return response;
}

void odpapi_scan_response_helper(cJSON *responsearray,
							    enum ODPAPI_SCANSTATUS status,
							    int sequence,
							    char* id,
							    char* type,
							    char* hint)
{
	cJSON* response = cJSON_CreateObject();
	cJSON_AddItemToArray(responsearray, response);

	cJSON_AddNumberToObject(response, "sequence", sequence);
	cJSON_AddNumberToObject(response, "status", status);

	if ( hint && strlen(hint) )
	{
		cJSON_AddStringToObject(response, "status_hint", hint);
	}

	if ( id && strlen(id) )
	{
		cJSON_AddStringToObject(response, "id", id);
	}

	if ( type && strlen(type) )
	{
		cJSON_AddStringToObject(response, "type", type);
	}
}

void odpapi_add_response_helper(cJSON *responsearray,
							    enum ODPAPI_ADDSTATUS status,
							    int sequence,
					            char* id,
							    char* hint)
{
	cJSON* response = cJSON_CreateObject();
	cJSON_AddItemToArray(responsearray, response);

	cJSON_AddNumberToObject(response, "sequence", sequence);
	cJSON_AddNumberToObject(response, "status", status);

	if ( hint && strlen(hint) )
	{
		cJSON_AddStringToObject(response, "status_hint", hint);
	}

	if ( id && strlen(id) )
	{
		cJSON_AddStringToObject(response, "id", id);
	}
}
